class Board
	
	class Trail
		
		def initialize(start)
		  @list = [start]
		end
		
		#assumes already oriented
		def can_play?(d)
		  d.tail == front.head
		end
		
		def front
			@list.last
		end
		
		def dominoes
			@list
		end
		
		def size
			@list.size
		end
		
		def add_to_end(d)
			@list << d
		end
		
		def dup
			dup_list = @list.inject([]){|memo, d| memo << d.dup; memo}
			t = Trail.new(nil)
			t.send(:set_list, dup_list)
			t
		end
		
		private
		
		def set_list(l)
		  @list = l
		end
		
	end
	
	
	def initialize
	  @trails = []
	  @spinner_played = false;
	end
	
	def init_game(start)
		new_trail(start)
		new_trail(Domino.new start.head, start.tail, start.spinner)
	end
	
	def size
	  if game_started?
	    @trails.inject(0) { |memo, t| t.size + memo } - @trails.size + 1
	  else
	    0
	  end
	end
	
	def new_trail(start)
	  #important to always put spinners after regular trails!
		if start.spinner
		  @trails << Trail.new(start)
		  @spinner_played = true
		else
		  @trails.insert(0, Trail.new(start))
		end
	end
	
	def spinner_playable?(s)
	  
	  num_identical = @trails.inject(0) do |memo, t|
	    if t.front  == s
	      memo = memo + 1
	    end
	    memo   
	  end
	  num_identical < 3
	end
	
	def get_unique_ends
	  visited = []
	  spinners_visited = []
	  ends = @trails.inject([]) do |memo, t|
	    
	    if t.front.spinner
	      if spinner_playable?(t.front)
	       memo << t.front unless spinners_visited.include? t.front.head
	       spinners_visited << t.front.head
	      end
	    else
	      memo << t.front unless visited.include? t.front.head
	      visited << t.front.head
	    end
	    memo
	  end
	end
	
	def legal_plays(d)
		plays = get_unique_ends.inject([]) do |memo, e|
			memo << e if d.to_a.include?(e.head)
			memo
		end
	end
	
	def game_started?
		!@trails.empty?
	end
	
	def has_spinner?
	  @spinner_played
	end
	
	def place_domino(new_domino, end_domino)
	  if !game_started?
	    init_game(new_domino)
	  elsif game_started? && new_domino.is_a?(Domino) && end_domino.is_a?(Domino)
	    new_domino.orient_with!(end_domino)
      t = trail_ending_exactly_with(end_domino)
      t.can_play?(new_domino) ? t.add_to_end(new_domino) : false
    else
      raise "Board needs two dominoes after game has started."
	  end
	end
	
	#must specify domino with correct ORDER!
	def trail_ending_exactly_with(d)
		@trails.find do |t| 
		  if t.size == 1 #order is important when size == 1 because two trails start/end with same dominoe
		    (t.front.head == d.head) && (t.front.tail == d.tail) && (t.front.spinner == d.spinner)
		  else
		    (t.front == d) && (t.front.spinner == d.spinner)
		  end
		end
	end
	
	def sum_ends
		@trails.inject(0) do |memo, t|
		  unless t.front.spinner
		    if t.front.is_double? && t.size > 1
		      memo = memo + t.front.value
		    else
		      memo = memo + t.front.head
		    end
		  end
			memo	
		end
	end
	
	def scoring_tiles(group)
	  
	  bc = sum_ends
	  ues = get_unique_ends
	  
	  group.inject([]) do |memo, d|
	    ues.each do |e|
	      adj = nil
	      if e.spinner
	        if d.head == e.head
	          adj = d.tail
          elsif d.tail == e.head
            adj = d.head
          end
	      
	      elsif e.is_double? && @trails.any?{|t| t.size > 1}
	        if d.head == e.head
	          adj = d.tail - 2*e.head
	        elsif d.tail == e.head
	          adj = d.head - 2*e.head
          end
          
	      elsif d.is_double?
	        if d.head == e.head
            adj = d.tail
          end
	      else
	        if d.head == e.head
            adj = d.tail - d.head
          elsif d.tail == e.head
            adj = d.head - d.tail
          end
	      end
	      memo << d if adj && ((adj + bc) % InteractiveDominos::SCORER == 0) && (adj + bc > 0)
	    end
	    memo
	  end
	end
	
	def to_s
	  s = ""
	  @trails.each do |t|
	    s << t.dominoes.to_s + "\n"
	  end
	  s + "Size: #{size} BC: #{sum_ends}"
	end
	
	def dup
	  b = Board.new
	  dup_trails = @trails.inject([]){|memo, t| memo << t.dup; memo}
	  b.send(:set_trails, dup_trails, @spinner_played)
	  b
	end
	
	private
	
	def set_trails(t, sp)
	  @spinner_played = sp
	  @trails = t
	end

end